package com.jianganming.netty.rpc.consumer;

import com.jianganming.netty.rpc.protocol.InvokerProtocol;
import com.jianganming.netty.rpc.registry.RegistryCenterWithZk;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class RpcProxy {
    private RegistryCenterWithZk registryCenterWithZk;
    private Class<?> clazz;
    public <T> T create(Class<T> clazz){
        this.clazz = clazz;
        return (T)Proxy.newProxyInstance(clazz.getClassLoader(),
                new Class[]{clazz}, (object, method, args) -> {
                    if (Object.class.equals(method.getDeclaringClass())) {
                        try {
                            return method.invoke(this, args);
                        } catch (Throwable t) {
                            t.printStackTrace();
                        }
                        //如果传进来的是一个接口（核心)
                    } else {
                        return rpcInvoke(object,method, args);
                    }

                    return null;
        });
    }

    private Object rpcInvoke(Object object, Method method, Object[] args) {
        //传输协议封装
        InvokerProtocol msg = new InvokerProtocol();
        msg.setClassName(this.clazz.getName());
        msg.setMethodName(method.getName());
        msg.setValues(args);
        msg.setParames(method.getParameterTypes());
        final RpcProxyHandler consumerHandler = new RpcProxyHandler();
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        try {
            registryCenterWithZk = RegistryCenterWithZk.getRegistryCenterWithZk().getData(msg.getClassName());
            //System.out.println(msg.getClassName());
            ChannelFuture future = b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            //自定义协议编码器
                            pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                            //对象参数类型编码器
                            pipeline.addLast("encoder", new ObjectEncoder());
                            //对象参数类型解码器
                            pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

                            pipeline.addLast("handler",consumerHandler);

                        }
                    }).connect(registryCenterWithZk.getIp(), registryCenterWithZk.getPort()).sync();

            future.channel().writeAndFlush(msg);
            future.channel().closeFuture().sync();

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
        return consumerHandler.getResponse();
    }

}
